package com.battery.system.service.battery.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.battery.common.core.domain.AjaxResult;
import com.battery.common.core.text.Convert;
import com.battery.common.enums.*;
import com.battery.common.utils.*;
import com.battery.common.utils.ali.AliPayEntity;
import com.battery.common.utils.ali.AliPayUtils;
import com.battery.common.utils.wx.PayscoreUtils;
import com.battery.common.utils.wx.SignUtils;
import com.battery.system.domain.*;
import com.battery.system.domain.BO.OrderBO;
import com.battery.system.domain.VO.OrderDetails;
import com.battery.system.domain.VO.OrderVO;
import com.battery.system.mapper.*;
import com.battery.system.service.battery.IIncomeService;
import com.battery.system.service.battery.IOrderService;
import com.battery.system.service.impl.BaseServiceImpl;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import org.apache.commons.lang3.StringUtils;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 支付订单Service业务层处理
 *
 * @author battery
 * @date 2021-01-22
 */
@Service
public class OrderServiceImpl extends BaseServiceImpl<Order> implements IOrderService {


    @Autowired
    private OrderMapper orderMapper;


    @Autowired
    private UsedMapper usedMapper;

    //  微信支付
    @Autowired(required = false)
    private WxPayService wxService;

    @Autowired
    private AppUserMapper appUserMapper;


    @Autowired
    private Sid sid;


    @Autowired
    private AuthUsedMapper authUsedMapper;


    @Autowired
    private RefundOrderMapper refundOrderMapper;


    @Autowired
    private IIncomeService incomeService;


    @Autowired
    private ProjectMapper projectMapper;


    /**
     * 查询支付订单
     *
     * @param id 支付订单ID
     * @return 支付订单
     */
    @Override
    public Order selectOrderById(String id) {
        return orderMapper.selectOrderById(id);
    }

    /**
     * 查询支付订单列表
     *
     * @param order 支付订单
     * @return 支付订单
     */
    @Override
    public List<Order> selectOrderList(Order order) {
        return orderMapper.selectOrderList(order);
    }

    /**
     * 新增支付订单
     *
     * @param order 支付订单
     * @return 结果
     */
    @Override
    public int insertOrder(Order order) {
        return orderMapper.insertOrder(order);
    }

    /**
     * 修改支付订单
     *
     * @param order 支付订单
     * @return 结果
     */
    @Override
    public int updateOrder(Order order) {
        return orderMapper.updateOrder(order);
    }

    /**
     * 删除支付订单对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteOrderByIds(String ids) {
        return orderMapper.deleteOrderByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除支付订单信息
     *
     * @param id 支付订单ID
     * @return 结果
     */
    @Override
    public int deleteOrderById(String id) {
        return orderMapper.deleteOrderById(id);
    }

    /**
     * 查询未使用的微信押金
     *
     * @param appUserId
     * @return
     */
    @Override
    public List<Order> noUsedWxDeposit(String appUserId) {
        Example example = new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appUserId", appUserId);
        criteria.andEqualTo("channel", UserTypeEnum.WX.getCode());
        criteria.andEqualTo("tradeState", OrderTradeStateEnum.PAY_SUCCESS.getCode());
        criteria.andEqualTo("orderType", OrderTypeEnum.DEPOSIT.type);
        criteria.andEqualTo("isUsed", YesOrNoEnum.NO.getCode());
        return orderMapper.selectByExample(example);
    }


    /**
     * 微信小程序支付统一下单
     *
     * @param appUser 用户信息
     * @param device  设备信息
     * @param amount  支付金额
     * @param type    状态
     * @param extra   扩展参数
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult wxPayRecharge(AppUser appUser, Device device, BigDecimal amount, Integer type, String extra) {

        Date date = DateUtils.getNowDate();

        String order_id = sid.nextShort();
        String outOrderNo = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);
        Order order = new Order();
        order.setId(order_id);
        order.setAppUserId(appUser.getId());
        order.setProjectId(device.getProjectId());
        order.setPartnerId(device.getPartnerId());
        order.setMerchantId(device.getMerchantId());
        order.setStoreId(device.getStoreId());
        order.setOutOrderNo(outOrderNo);
        order.setChannel(appUser.getUserType());
        order.setTotalFee(amount);
        order.setTradeState(OrderTradeStateEnum.UNPAID.getCode());
        order.setCreatedTime(date);
        order.setSn(device.getSn());
        order.setPayType(OrderPayTypeEnum.WX_PAY.getCode());

        String body = "";
        String brand_name = "免电";
        Used used = null;
        if (type == 1) {
            body = brand_name + "-" + "押金";
            order.setOrderType(OrderTypeEnum.DEPOSIT.type);
        } else if (type == 2) {
            body = brand_name + "-" + "机柜租赁费用";
            order.setOrderType(OrderTypeEnum.DEV_BORROW_COST.type);

            String used_id = extra;
            order.setExtend(used_id);
            used = usedMapper.selectByPrimaryKey(used_id);
            order.setUsedId(used_id);

        } else if (type == 3) {
            body = brand_name + "-" + "线租借费用";
            order.setOrderType(OrderTypeEnum.LINE_BORROW_COST.type);
            order.setExtend(extra); // 保存额外参数，支付的时长
        }
        orderMapper.insertSelective(order);

        if (used != null) {
            // 机柜租赁费用，保存真正订单ID
            Used usedUpdate = new Used();
            usedUpdate.setId(used.getId());
            usedUpdate.setTrueOrderId(order_id);
            usedMapper.updateByPrimaryKeySelective(usedUpdate);
        }

        WxPayUnifiedOrderRequest unifiedOrderRequest = new WxPayUnifiedOrderRequest();
        unifiedOrderRequest.setOutTradeNo(outOrderNo);
        unifiedOrderRequest.setBody(body);
        unifiedOrderRequest.setTotalFee(new BigDecimal(100).multiply(amount).intValue());
        unifiedOrderRequest.setOpenid(appUser.getAppUserCode());
        unifiedOrderRequest.setNotifyUrl(Constants.wx_pay_callback_url);
        unifiedOrderRequest.setTradeType("JSAPI");
        unifiedOrderRequest.setSpbillCreateIp(Constants.spbill_create_ip);
        WxPayUnifiedOrderResult result = null;
        try {
            result = wxService.unifiedOrder(unifiedOrderRequest);
        } catch (Exception e) {
            e.printStackTrace();
            return BatteryJSONResult.errorMsg("发起统一下单失败，请联系管理员");
        }
        if (result == null) {
            return BatteryJSONResult.errorMsg("发起统一下单失败，请联系管理员");
        }
        if ("SUCCESS".equals(result.getReturnCode()) && "SUCCESS".equals(result.getResultCode())) {
            // 统一下单成功
            Map<String, String> paramsMap = new HashMap<>();
            paramsMap.put("appId", Constants.wxMinAppID); // result.getPrepayId();
            paramsMap.put("timeStamp", CommonUtils.getCurrentTimestamp() + "");
            paramsMap.put("nonceStr", CommonUtils.generateUUID(16));
            paramsMap.put("package", "prepay_id=" + result.getPrepayId());
            paramsMap.put("signType", "MD5");
            String sign = SignUtils.signMd5(paramsMap, Constants.wxMerchantKey, new String[0]);
            paramsMap.put("paySign", sign);
            JSONObject requestJsonObj = new JSONObject();
            requestJsonObj.put("params", JSONObject.parseObject(JSON.toJSONString(paramsMap)));
            requestJsonObj.put("order_id", order.getId()); // 订单ID
            return BatteryJSONResult.ok(requestJsonObj);
        }
        return BatteryJSONResult.errorMsg(result.getErrCodeDes()); // 返回报错原因
    }

    /**
     * @param out_trade_no
     * @return
     */
    @Override
    public Order selectByOutTradeNo(String out_trade_no) {
        Example example = new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("outOrderNo", out_trade_no);
        return orderMapper.selectOneByExample(example);
    }

    /**
     * 微信小程序支付业务处理
     *
     * @param order          支付订单
     * @param transaction_id
     * @return
     */
    @Transactional
    @Override
    public String wxPayNotifyOrder(Order order, String transaction_id) {

        Date date = DateUtils.getNowDate();
        // 更新订单支付状态为成功
        Order orderUpdate = new Order();
        orderUpdate.setId(order.getId());
        orderUpdate.setTransactionId(transaction_id);
        orderUpdate.setPayTime(date);
        orderUpdate.setTradeState(OrderTradeStateEnum.PAY_SUCCESS.getCode());
        orderMapper.updateByPrimaryKeySelective(orderUpdate);

        // 支付订单类型
        Integer orderType = order.getOrderType();
        if (OrderTypeEnum.DEV_BORROW_COST.type.intValue() == orderType) {
            // 机柜租借费用
            Used usedUpdate = new Used();
            usedUpdate.setId(order.getExtend()); // 机柜租借费用扩展存储的是租借记录ID
            usedUpdate.setTrueOrderId(order.getId());
            usedUpdate.setStatus(UsedStatusEnum.PAID.getCode()); // 更新租借订单为已支付
            usedUpdate.setPaymentTime(date);
            usedMapper.updateByPrimaryKeySelective(usedUpdate);

            // 同时要保证是押金租借
            Used used = usedMapper.selectByPrimaryKey(order.getExtend());
            if (BorrowModeEnum.DEPOSIT.type.intValue() == used.getBorrowMode().intValue()) {
                // 押金租借订单
                AppUser appUser = appUserMapper.selectByPrimaryKey(order.getAppUserId());
                BigDecimal balance = appUser.getBalance();
                if (balance.compareTo(BigDecimal.ZERO) < 0) {
                    AppUser userUpdate = new AppUser();
                    userUpdate.setId(appUser.getId());
                    userUpdate.setBalance(appUser.getBalance().add(order.getTotalFee()));
                    appUserMapper.updateByPrimaryKeySelective(userUpdate);
                }
            } else if (BorrowModeEnum.FREE_DEPOSIT.type.intValue() == used.getBorrowMode().intValue()) {
                // 免押租借订单，未支付的订单处理
                AuthUsed authUsed = authUsedMapper.selectByPrimaryKey(used.getId());
                // TODO TODO 同步服务订单信息API取消订单 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_20.shtml

                String out_order_no = authUsed.getOutOrderNo();
                try {
                    JSONObject createObj = new JSONObject();
                    createObj.put("appid", Constants.wxMinAppID); // 微信小程序APPID
                    createObj.put("service_id", Constants.wxServiceId);// 微信支付分服务ID
                    createObj.put("type", "Order_Paid");// 场景类型为“Order_Paid”，字符串表示“订单收款成功”
                    JSONObject detailObj = new JSONObject();
                    detailObj.put("paid_time", DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, date));
                    createObj.put("detail", detailObj);
                    String merchantId = Constants.wxMerchantId;
                    String certSerialNo = Constants.certSerialNo; // 微信支付证书序列号
                    BatteryJSONResult result = PayscoreUtils.sync(createObj, out_order_no, merchantId, certSerialNo, Constants.wx_cret_keyPath_apiclient_key);
                    if (result.getCode() == 0) {
                        // TODO TODO 同步服务订单信息请求失败
                        return WxPayNotifyResponse.success("成功");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            // TODO TODO 进行分润操作
            try {
                incomeService.shareMoney(used.getId(), order.getId());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return WxPayNotifyResponse.success("成功");
    }

    /**
     * @param appUserId
     * @return
     */
    @Override
    public List<Order> noUsedALiDeposit(String appUserId) {
        Example example = new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appUserId", appUserId);
        criteria.andEqualTo("channel", UserTypeEnum.ALI.getCode());
        criteria.andEqualTo("tradeState", OrderTradeStateEnum.PAY_SUCCESS.getCode());
        criteria.andEqualTo("orderType", OrderTypeEnum.DEPOSIT.type);
        criteria.andEqualTo("isUsed", YesOrNoEnum.NO.getCode());
        return orderMapper.selectByExample(example);
    }

    /**
     * 支付宝支付 统一下单
     *
     * @param appUser 用户信息
     * @param device  设备信息
     * @param amount  支付金额
     * @param type    订单类型
     * @param extra   扩展参数
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult aliPayRecharge(AppUser appUser, Device device, BigDecimal amount, Integer type, String extra, AliPayEntity entity) {

        Date date = DateUtils.getNowDate();
        String order_id = sid.nextShort();
        String outOrderNo = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);
        Order order = new Order();
        order.setId(order_id);
        order.setAppUserId(appUser.getId());
        order.setProjectId(device.getProjectId());
        order.setPartnerId(device.getPartnerId());
        order.setMerchantId(device.getMerchantId());
        order.setStoreId(device.getStoreId());
        order.setOutOrderNo(outOrderNo);
        order.setChannel(appUser.getUserType());
        order.setTotalFee(amount);
        order.setTradeState(OrderTradeStateEnum.UNPAID.getCode());
        order.setCreatedTime(date);
        order.setSn(device.getSn());
        order.setPayType(OrderPayTypeEnum.ZFB_PAY.getCode());

        String body = "";
        Used used = null;
        if (type == 1) {
            body = "免电" + "-" + "押金";
            order.setOrderType(OrderTypeEnum.DEPOSIT.type);
        } else if (type == 2) {
            body = "免电" + "-" + "机柜租赁费用";
            order.setOrderType(OrderTypeEnum.DEV_BORROW_COST.type);

            String used_id = extra;
            order.setExtend(used_id);
            used = usedMapper.selectByPrimaryKey(used_id);
            order.setUsedId(used_id);
        } else if (type == 3) {
            body = "免电" + "-" + "线租借费用";
            order.setOrderType(OrderTypeEnum.LINE_BORROW_COST.type);
            order.setExtend(extra); // 保存额外参数
        }
        orderMapper.insertSelective(order);

        if (used != null) {
            // 机柜租赁费用，保存真正订单ID
            Used usedUpdate = new Used();
            usedUpdate.setId(used.getId());
            usedUpdate.setTrueOrderId(order_id);
            usedMapper.updateByPrimaryKeySelective(usedUpdate);
        }
        // 创建订单
        JSONObject object = new JSONObject();
        object.put("out_trade_no", outOrderNo);
        object.put("total_amount", amount);
        object.put("subject", body);
        object.put("buyer_id", appUser.getAppUserCode());
        object.put("notifyUrl", Constants.ali_pay_notify_url); // 支付宝支付回调地址
        BatteryJSONResult responseJSON = AliPayUtils.generateTrade(entity, object);
        if (responseJSON.getCode() != 1) {
            // 创建订单失败
            return BatteryJSONResult.errorMsg(responseJSON.getMsg());
        }
        String trade_no = (String) responseJSON.getData();
        Order updateOrder = new Order();
        updateOrder.setId(order_id);
        updateOrder.setTransactionId(trade_no);
        orderMapper.updateByPrimaryKeySelective(updateOrder);
        JSONObject requestJson = new JSONObject();
        requestJson.put("trade_no", trade_no); // 支付宝交易号
        requestJson.put("order_id", order.getId());
        return BatteryJSONResult.ok(requestJson);
    }

    /**
     * 支付宝支付回调处理
     *
     * @param order            支付订单
     * @param queryTradeStatus 支付订单状态
     * @return
     */
    @Override
    public String aliPayNotifyOrder(Order order, String queryTradeStatus) {
        if ("TRADE_CLOSED".equals(queryTradeStatus)) {
            // TRADE_CLOSED（未付款交易超时关闭，或支付完成后全额退款）
            Order orderUpdate = new Order();
            orderUpdate.setId(order.getId());
            orderUpdate.setTradeState(OrderTradeStateEnum.CLOSED.getCode()); // 支付交易关闭
            orderMapper.updateByPrimaryKeySelective(orderUpdate);
            return "success";
        }
        if ("TRADE_SUCCESS".equals(queryTradeStatus)) {
            // 交易支付成功
            Date date = DateUtils.getNowDate();
            Order orderUpdate = new Order();
            orderUpdate.setId(order.getId());
            orderUpdate.setPayTime(date);
            orderUpdate.setTradeState(OrderTradeStateEnum.PAY_SUCCESS.getCode());
            orderMapper.updateByPrimaryKeySelective(orderUpdate);

            // 支付订单类型
            Integer orderType = order.getOrderType();
            if (OrderTypeEnum.DEV_BORROW_COST.type.intValue() == orderType) {
                // 机柜租借费用
                Used usedUpdate = new Used();
                usedUpdate.setId(order.getExtend()); // 机柜租借费用扩展存储的是租借记录ID
                usedUpdate.setTrueOrderId(order.getId());
                Project project = projectMapper.selectByPrimaryKey(order.getProjectId());
                BigDecimal deposit = new BigDecimal(99);
                if (project != null) {
                    deposit = project.getDeposit();
                }
                if (deposit.subtract(order.getTotalFee()).compareTo(BigDecimal.ZERO) == 0) {
                    usedUpdate.setStatus(UsedStatusEnum.PURCHASED.getCode()); // 更新租借订单为已购买
                } else {
                    usedUpdate.setStatus(UsedStatusEnum.PAID.getCode()); // 更新租借订单为已支付
                }
                usedUpdate.setPaymentTime(date);
                usedMapper.updateByPrimaryKeySelective(usedUpdate);

                // 注意 存在预授权未支付的情况，所以要判断用户租借订单
                Used used = usedMapper.selectByPrimaryKey(order.getExtend());
                if (BorrowModeEnum.DEPOSIT.type.intValue() == used.getBorrowMode().intValue()) {
                    // 押金订单
                    AppUser appUser = appUserMapper.selectByPrimaryKey(order.getAppUserId());
                    BigDecimal balance = appUser.getBalance();
                    if (balance.compareTo(BigDecimal.ZERO) < 0) {
                        AppUser userUpdate = new AppUser();
                        userUpdate.setId(appUser.getId());
                        userUpdate.setBalance(appUser.getBalance().add(order.getTotalFee()));
                        appUserMapper.updateByPrimaryKeySelective(userUpdate);
                    }
                }
                // TODO TODO 也需要判断预授权支付订单是否已经解冻撤销
                // TODO TODO 进行分润操作
                try {
                    incomeService.shareMoney(order.getUsedId(), order.getId());
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
        return "success";
    }

    /**
     * @param order    支付订单
     * @param authUsed 授权订单
     * @param params
     * @return
     */
    @Transactional
    @Override
    public String aliFreezePayNotify(Order order, AuthUsed authUsed, Map<String, String> params) {

        String trade_no = params.get("trade_no");
        String gmt_payment = params.get("gmt_payment");

        Date payTime = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, gmt_payment);
        Order updateOrder = new Order();
        updateOrder.setId(order.getId());
        updateOrder.setTransactionId(trade_no);
        updateOrder.setTradeState(OrderTradeStateEnum.PAY_SUCCESS.getCode()); // 设置为已支付
        updateOrder.setPayTime(payTime);
        updateOrder.setUsedId(authUsed.getUsedId());
        orderMapper.updateByPrimaryKeySelective(updateOrder);

        AuthUsed authUsedUpdate = new AuthUsed();
        authUsedUpdate.setUsedId(authUsed.getUsedId());
        authUsedUpdate.setState(UsedAuthStateEnum.PAID.type);
        authUsedUpdate.setStateDescription(UsedAuthStateDescriptionEnum.USER_PAID.type);
        authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);

        Used usedUpdate = new Used();
        usedUpdate.setStatus(UsedStatusEnum.PAID.getCode());
        usedUpdate.setPaymentTime(payTime);
        usedUpdate.setId(authUsed.getUsedId());
        usedMapper.updateByPrimaryKeySelective(usedUpdate);

        // TODO TODO 开始分成
        try {
            incomeService.shareMoney(authUsed.getUsedId(), order.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "success";
    }


    @Override
    public List<OrderVO> selectOrderVOList(OrderBO orderBO) {
        return orderMapper.selectOrderVOList(orderBO);
    }

    @Override
    public OrderDetails selectOrderUsedIncome(String id) {
        return orderMapper.selectOrderUsedIncome(id);
    }

    /**
     * 后台退押金操作
     *
     * @param orderId      支付订单ID
     * @param aliPayEntity
     * @return
     */
    @Transactional
    @Override
    public AjaxResult backstageRefundDeposit(String orderId, AliPayEntity aliPayEntity) {
        Order order = orderMapper.selectByPrimaryKey(orderId);
        AppUser appUser = appUserMapper.selectByPrimaryKey(order.getAppUserId());


        // TODO 查询该用户是否存在正在进行中的订单
        Example exampleOnUseds = new Example(Used.class);
        Example.Criteria criteriaOnUseds = exampleOnUseds.createCriteria();
        criteriaOnUseds.andEqualTo("leaseState", LeaseStateEnum.SUCCESS.getCode());
        criteriaOnUseds.andEqualTo("isBack", YesOrNoEnum.NO.getCode());
        criteriaOnUseds.andEqualTo("appUserId", appUser.getId());
        exampleOnUseds.orderBy("createTime").desc();
        if (usedMapper.selectCountByExample(exampleOnUseds) > 0) {
            return AjaxResult.error("该用户存在正在进行中的订单,不可退押");
        }

        BigDecimal balance = appUser.getBalance();
        BigDecimal refund_fee = null; // 退款金额
        BigDecimal absBalance = balance.abs();// 用户余额
        if (balance.compareTo(BigDecimal.ZERO) < 0) {
            // 存在欠款金额
            refund_fee = order.getTotalFee().subtract(absBalance);
        } else {
            refund_fee = order.getTotalFee();
        }
        if (refund_fee.compareTo(BigDecimal.ZERO) <= 0) {
            return AjaxResult.error("该用户欠款金额大于押金金额，无法退款!");
        }
        Example example = new Example(RefundOrder.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("orderId", order.getId());
        criteria.andEqualTo("refundStatus", RefundStatusEnum.CHANGE.getCode()); // 退款异常
        RefundOrder errRefund = refundOrderMapper.selectOneByExample(example);
        String out_refund_no = ""; // 退款单号
        String refundOrderId = null;
        if (errRefund != null) {
            out_refund_no = errRefund.getOutRefundNo();
            RefundOrder orderUpdate = new RefundOrder();
            orderUpdate.setId(errRefund.getId());
            orderUpdate.setRefundFee(refund_fee);
            orderUpdate.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
            refundOrderMapper.updateByPrimaryKeySelective(orderUpdate);

            refundOrderId = errRefund.getId();
        } else {
            out_refund_no = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);

            RefundOrder refundOrder = new RefundOrder();
            refundOrder.setId(sid.nextShort());
            refundOrder.setAppUserId(appUser.getId());
            refundOrder.setOutRefundNo(out_refund_no);
            refundOrder.setTotalFee(order.getTotalFee());
            refundOrder.setRefundFee(refund_fee);
            refundOrder.setRefundDesc("后台-退押金");
            refundOrder.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
            refundOrder.setCreateTime(DateUtils.getNowDate());
            refundOrder.setOrderId(order.getId());
            refundOrder.setOrderType(order.getOrderType());
            refundOrder.setChannel(order.getChannel());
            refundOrderMapper.insertSelective(refundOrder);
            // 查询新建的退款数据
            refundOrderId = refundOrder.getId();
        }
        // 订单渠道 微信 1 支付宝 2
        if (order.getChannel().intValue() == 1) {
            // 微信
            // 发起退款操作
            WxPayRefundRequest refundRequest = new WxPayRefundRequest();
            refundRequest.setTransactionId(order.getTransactionId());
            refundRequest.setOutRefundNo(out_refund_no);
            refundRequest.setTotalFee(order.getTotalFee().multiply(new BigDecimal(100)).intValue());
            refundRequest.setRefundFee(refund_fee.multiply(new BigDecimal(100)).intValue());
            refundRequest.setNotifyUrl(Constants.wx_refund_callback_url); // 退款通知接口
            WxPayRefundResult refundResult = null;
            boolean flag = false;
            try {
                refundResult = wxService.refund(refundRequest);
            } catch (WxPayException e) {
                // 发生错误
                e.printStackTrace();
                flag = true;
            }
            if (refundResult == null || flag) {
                // 调起微信退款接口发生错误
                RefundOrder updateRefundOrder = new RefundOrder();
                updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
                updateRefundOrder.setId(refundOrderId);
                updateRefundOrder.setRemark("发起退押出现异常");
                refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);

                return AjaxResult.error("发起退押出现异常");
            }
            String return_code = refundResult.getReturnCode();
            String result_code = refundResult.getResultCode();
            if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) {
                // 发起退款接口成功，更新退款订单号
                String refund_id = refundResult.getRefundId(); // 微信退款单号
                RefundOrder updateOrder = new RefundOrder();
                updateOrder.setId(refundOrderId);
                updateOrder.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
                updateOrder.setRefundId(refund_id);
                refundOrderMapper.updateRefundOrder(updateOrder);

                // 更新原先订单状态
                Order updateFormer = new Order();
                updateFormer.setId(order.getId());
                updateFormer.setTradeState(OrderTradeStateEnum.TO_REFUND.getCode()); // 转入退款
                updateFormer.setRefundId(out_refund_no); // 退款订单号
                updateFormer.setRefundMoney(refund_fee); // 退款金额
                orderMapper.updateByPrimaryKeySelective(updateFormer);
                return AjaxResult.success("退押成功，退款金额为" + refund_fee + "元");
            }
            // 调起微信退款接口发生错误
            RefundOrder updateRefundOrder = new RefundOrder();
            updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
            updateRefundOrder.setId(refundOrderId);
            updateRefundOrder.setRemark("发起退押出现异常");
            refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
            return AjaxResult.error("退押失败,微信返回【" + refundResult.getErrCodeDes() + "】"); // 返回错误描述
        } else {
            // 支付宝
            JSONObject requestRefundObj = new JSONObject();
            requestRefundObj.put("out_trade_no", order.getOutOrderNo());
            requestRefundObj.put("trade_no", order.getTransactionId());
            requestRefundObj.put("out_request_no", out_refund_no);
            requestRefundObj.put("refund_amount", refund_fee);
            BatteryJSONResult result = null;
            boolean flag = false;
            try {
                result = AliPayUtils.tradeRefund(aliPayEntity, requestRefundObj);
            } catch (Exception e) {
                e.printStackTrace();
                flag = true;
            }
            if (result == null || flag || result.getCode().intValue() != 1) {
                // 支付宝退款抛出异常
                RefundOrder updateRefundOrder = new RefundOrder();
                updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
                updateRefundOrder.setId(refundOrderId);
                updateRefundOrder.setRemark("发起退押出现异常");
                refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
                return AjaxResult.error("发起退押出现异常");
            }
            AlipayTradeRefundResponse response = (AlipayTradeRefundResponse) result.getData();
            if (response.isSuccess()) {
                Date paySuccessTime = DateUtils.getNowDate();
                // 退款成功
                RefundOrder updateOrder = new RefundOrder();
                updateOrder.setId(refundOrderId);
                updateOrder.setRefundStatus(RefundStatusEnum.SUCCESS.getCode());
                updateOrder.setSuccessTime(paySuccessTime);
                refundOrderMapper.updateByPrimaryKeySelective(updateOrder);

                // 支付宝直接设定为退款成功

                // 更新原先订单状态
                Order updateFormer = new Order();
                updateFormer.setId(order.getId());
                updateFormer.setTradeState(OrderTradeStateEnum.REFUND_SUCCESS.getCode()); // 转入退款
                updateFormer.setRefundId(out_refund_no); // 退款订单号
                updateFormer.setRefundMoney(refund_fee); // 退款金额
                orderMapper.updateByPrimaryKeySelective(updateFormer);


                // TODO 退款成功之后，进行退分润，或者进行分润操作，将欠费基恩补足
                if (absBalance.compareTo(BigDecimal.ZERO) > 0) {
                    // 存在欠款金额，欠款金额需要进行正常分润操作

                    // 查询该用户最新未付款金额, 押金租借，未付款订单
                    Example exampleUsed = new Example(Used.class);
                    Example.Criteria criteriaUsed = exampleUsed.createCriteria();
                    criteriaUsed.andEqualTo("leaseState", LeaseStateEnum.SUCCESS.getCode()); // 租借成功
                    criteriaUsed.andEqualTo("isBack", YesOrNoEnum.YES.getCode()); // 归还成功
                    criteriaUsed.andEqualTo("appUserId", appUser.getId());
                    criteriaUsed.andEqualTo("channel", order.getChannel());
                    criteriaUsed.andEqualTo("borrowMode", BorrowModeEnum.DEPOSIT.type);
                    criteriaUsed.andEqualTo("status", UsedStatusEnum.TO_BE_PAID.getCode()); // 待支付
                    exampleUsed.orderBy("createTime").desc();
                    Used noPayAliUsed = usedMapper.selectOneByExample(exampleUsed);
                    if (noPayAliUsed != null && noPayAliUsed.getAmountPaid().compareTo(absBalance) == 0) {
                        // 用户押金租借，未支付金额，后台已经退款成功，则将该笔订单设置为已支付
                        Used usedUpdate = new Used();
                        usedUpdate.setId(noPayAliUsed.getId());
                        usedUpdate.setStatus(UsedStatusEnum.PAID.getCode()); // 更新租借订单为已支付
                        usedUpdate.setPaymentTime(paySuccessTime); // 支付成功实践
                        // TODO TODO 是否要保存真实支付订单ID
                        usedMapper.updateByPrimaryKeySelective(usedUpdate);

                        AppUser userUpdate = new AppUser();
                        userUpdate.setId(appUser.getId());
                        userUpdate.setBalance(appUser.getBalance().add(noPayAliUsed.getAmountPaid()));
                        appUserMapper.updateByPrimaryKeySelective(userUpdate);

                        // TODO TODO 同时开始进行分润操作

                    }
                }
                return AjaxResult.success("退押成功，退款金额为" + refund_fee + "元");
            }
            RefundOrder updateRefundOrder = new RefundOrder();
            updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
            updateRefundOrder.setId(refundOrderId);
            updateRefundOrder.setRemark("发起退押出现异常");
            refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
            return AjaxResult.error("退押失败,支付宝返回【" + response.getSubMsg() + "】"); // 返回错误描述
        }

    }

    /**
     * 后台 退款操作
     *
     * @param updateOrder
     * @param aliPayEntity
     * @return
     */
    @Transactional
    @Override
    public AjaxResult backstageRefundMoney(Order updateOrder, AliPayEntity aliPayEntity) {

        BigDecimal refund_fee = updateOrder.getRefundMoney(); // 需退款金额
        String refundDesc = updateOrder.getRefundDesc();
        String orderId = updateOrder.getId();

        Order order = orderMapper.selectByPrimaryKey(orderId);
        // 查询是否存在对应退款失败订单
        Example example = new Example(RefundOrder.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("orderId", orderId);
        criteria.andEqualTo("refundStatus", RefundStatusEnum.CHANGE.getCode()); // 退款异常
        RefundOrder errRefund = refundOrderMapper.selectOneByExample(example);


        AppUser appUser = appUserMapper.selectByPrimaryKey(order.getAppUserId());

        String out_refund_no = ""; // 退款单号
        String refundOrderId = null;
        if (errRefund != null) {
            out_refund_no = errRefund.getOutRefundNo();
            RefundOrder orderUpdate = new RefundOrder();
            orderUpdate.setId(errRefund.getId());
            orderUpdate.setRefundFee(refund_fee);
            orderUpdate.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款

            refundOrderMapper.updateByPrimaryKeySelective(orderUpdate);

            refundOrderId = errRefund.getId();
        } else {
            out_refund_no = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);

            RefundOrder refundOrder = new RefundOrder();
            refundOrder.setId(sid.nextShort());
            refundOrder.setAppUserId(appUser.getId());
            refundOrder.setOutRefundNo(out_refund_no);
            refundOrder.setTotalFee(order.getTotalFee());
            refundOrder.setRefundFee(refund_fee);
            refundOrder.setRefundDesc(refundDesc); // 退款描述
            refundOrder.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
            refundOrder.setCreateTime(DateUtils.getNowDate());
            refundOrder.setOrderId(order.getId());
            refundOrder.setOrderType(order.getOrderType());
            refundOrder.setChannel(order.getChannel());
            refundOrderMapper.insertSelective(refundOrder);
            // 查询新建的退款数据
            refundOrderId = refundOrder.getId();
        }

        // 订单渠道 微信 1 支付宝 2
        if (order.getChannel().intValue() == 1) {
            WxPayRefundRequest refundRequest = new WxPayRefundRequest();
            refundRequest.setTransactionId(order.getTransactionId());
            refundRequest.setOutRefundNo(out_refund_no);
            refundRequest.setTotalFee(order.getTotalFee().multiply(new BigDecimal(100)).intValue());
            refundRequest.setRefundFee(refund_fee.multiply(new BigDecimal(100)).intValue());
            refundRequest.setNotifyUrl(Constants.wx_refund_callback_url); // 退款通知接口
            WxPayRefundResult refundResult = null;
            boolean flag = false;
            try {
                refundResult = wxService.refund(refundRequest);
            } catch (WxPayException e) {
                // 发生错误
                e.printStackTrace();
                flag = true;
            }
            if (refundResult == null || flag) {
                // 调起微信退款接口发生错误
                RefundOrder updateRefundOrder = new RefundOrder();
                updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
                updateRefundOrder.setId(refundOrderId);
                updateRefundOrder.setRemark("发起退款出现异常");
                refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
                return AjaxResult.error("发起退款出现异常");
            }
            String return_code = refundResult.getReturnCode();
            String result_code = refundResult.getResultCode();
            if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) {
                String refund_id = refundResult.getRefundId(); // 微信退款单号
                RefundOrder updateRefundOrder = new RefundOrder();
                updateRefundOrder.setId(refundOrderId);
                updateRefundOrder.setRefundId(refund_id);
                updateRefundOrder.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
                refundOrderMapper.updateRefundOrder(updateRefundOrder);

                // 更新原先订单状态
                Order updateFormer = new Order();
                updateFormer.setId(order.getId());
                updateFormer.setTradeState(OrderTradeStateEnum.TO_REFUND.getCode()); // 转入退款
                updateFormer.setRefundId(out_refund_no); // 退款订单号
                updateFormer.setRefundMoney(refund_fee); // 退款金额
                updateFormer.setRefundDesc(refundDesc); // 退款描述
                orderMapper.updateByPrimaryKeySelective(updateFormer);

                // TODO TODO 注意：微信进行退款操作，更新租借记录信息 在回调里面进行操作

                return AjaxResult.success("退款成功，退款金额为" + refund_fee + "元");
            }
            // 调起微信退款接口发生错误
            RefundOrder updateRefundOrder = new RefundOrder();
            updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
            updateRefundOrder.setId(refundOrderId);
            updateRefundOrder.setRemark("发起退款出现异常");
            refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
            return AjaxResult.error("退款失败,微信返回【" + refundResult.getErrCodeDes() + "】"); // 返回错误描述
        } else {
            // 支付宝退款
            JSONObject requestRefundObj = new JSONObject();
            requestRefundObj.put("out_trade_no", order.getOutOrderNo());
            requestRefundObj.put("trade_no", order.getTransactionId());
            requestRefundObj.put("out_request_no", out_refund_no);
            requestRefundObj.put("refund_amount", refund_fee);
            BatteryJSONResult result = null;
            boolean flag = false;
            try {
                result = AliPayUtils.tradeRefund(aliPayEntity, requestRefundObj);
            } catch (Exception e) {
                e.printStackTrace();
                flag = true;
            }
            if (result == null || flag || result.getCode().intValue() != 1) {
                // 支付宝退款抛出异常
                RefundOrder updateRefundOrder = new RefundOrder();
                updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
                updateRefundOrder.setId(refundOrderId);
                updateRefundOrder.setRemark("发起退款出现异常");
                refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
                return AjaxResult.error("发起退款出现异常");
            }
            AlipayTradeRefundResponse response = (AlipayTradeRefundResponse) result.getData();
            if (response.isSuccess()) {
                Date paySuccessTime = DateUtils.getNowDate();
                // 退款成功
                RefundOrder updateRefundOrder = new RefundOrder();
                updateRefundOrder.setId(refundOrderId);
                updateRefundOrder.setRefundStatus(RefundStatusEnum.SUCCESS.getCode());
                updateRefundOrder.setSuccessTime(paySuccessTime);
                refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);

                // 支付宝直接设定为退款成功
                // 更新原先订单状态
                Order updateFormer = new Order();
                updateFormer.setId(order.getId());
                updateFormer.setTradeState(OrderTradeStateEnum.REFUND_SUCCESS.getCode()); // 转入退款
                updateFormer.setRefundId(out_refund_no); // 退款订单号
                updateFormer.setRefundMoney(refund_fee); // 退款金额
                orderMapper.updateByPrimaryKeySelective(updateFormer);

                // TODO TODO 退款成功之后，更新对应租借订单状态
                if (StringUtils.isNotBlank(order.getUsedId())) {
                    Used usedUpdate = new Used();
                    usedUpdate.setId(order.getUsedId());
                    usedUpdate.setRefundAmount(refund_fee);
                    usedUpdate.setStatus(UsedStatusEnum.REFUND_SUCCESS.getCode());
                    usedMapper.updateByPrimaryKeySelective(usedUpdate);
                }
                // TODO TODO 退款成功之后，进行退分润操作
                try {
                    // 进行退分润操作
                    incomeService.refundShareMoney(order.getUsedId(), order.getId(), refundOrderId);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                return AjaxResult.success("退款成功，退款金额为" + refund_fee + "元");
            }
            RefundOrder updateRefundOrder = new RefundOrder();
            updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
            updateRefundOrder.setId(refundOrderId);
            updateRefundOrder.setRemark("发起退款出现异常");
            refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
            return AjaxResult.error("退款失败,支付宝返回【" + response.getSubMsg() + "】"); // 返回错误描述
        }
    }

    /**
     * 查询该用户是否存在支付完毕但是未出密码的支付订单
     *
     * @param appUserId
     * @param sn
     * @return
     */
    @Override
    public Order isHasOrderNotLineOrder(String appUserId, String sn) {
//        Example example = new Example(Order.class);
//        Example.Criteria criteria = example.createCriteria();
//        criteria.andEqualTo("orderType", OrderTypeEnum.LINE_BORROW_COST.type);
//        criteria.andEqualTo("tradeState", OrderTradeStateEnum.PAY_SUCCESS.getCode());
//        criteria.andEqualTo("sn", sn);
//        criteria.andEqualTo("appUserId", appUserId);
//        criteria.andIsNull("usedId");
//        example.orderBy("createdTime").desc();
        return orderMapper.isHasOrderNotLineOrder(appUserId, sn);
    }

    /**
     * 查询用户正常押金且未标记的押金
     *
     * @param appUserId
     * @return
     */
    @Override
    public List<Order> noUsedWxDepositNoSign(String appUserId) {
        Example example = new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appUserId", appUserId);
        criteria.andEqualTo("channel", UserTypeEnum.WX.getCode());
        criteria.andEqualTo("tradeState", OrderTradeStateEnum.PAY_SUCCESS.getCode());
        criteria.andEqualTo("orderType", OrderTypeEnum.DEPOSIT.type);
        criteria.andEqualTo("isUsed", YesOrNoEnum.NO.getCode());
        criteria.andEqualTo("isDepositSign", YesOrNoEnum.NO.getCode()); // 标记
        return orderMapper.selectByExample(example);
    }

    /**
     * 查询用户正常押金之和
     *
     * @param appUserId
     * @return
     */
    @Override
    public BigDecimal noUsedWxDepositSum(String appUserId) {
        return orderMapper.noUsedWxDepositSum(appUserId);
    }

    /**
     * 查询该支付宝用户正常押金之和
     *
     * @param appUserId
     * @return
     */
    @Override
    public BigDecimal noUsedAliDepositSum(String appUserId) {
        return orderMapper.noUsedAliDepositSum(appUserId);
    }

    /**
     * 查询该用户未标记的正常押金信息（支付宝）
     *
     * @param appUserId
     * @return
     */
    @Override
    public List<Order> noUsedALiDepositNoSign(String appUserId) {
        Example example = new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appUserId", appUserId);
        criteria.andEqualTo("channel", UserTypeEnum.ALI.getCode());
        criteria.andEqualTo("tradeState", OrderTradeStateEnum.PAY_SUCCESS.getCode());
        criteria.andEqualTo("orderType", OrderTypeEnum.DEPOSIT.type);
        criteria.andEqualTo("isUsed", YesOrNoEnum.NO.getCode());
        criteria.andEqualTo("isDepositSign", YesOrNoEnum.NO.getCode()); // 标记
        return orderMapper.selectByExample(example);
    }
}
